//
//  SelectContactViewModel.swift
//  MoyoungDevice
//
//  Created by 易先生 on 2022/9/5.
//

import UIKit
import Contacts
import RxCocoa
import RxSwift
import CRPEarPhone
import EarbudsDatabase

class SelectContactViewModel: NSObject {

	public var dataArray: [String: [ContactModel]] = [:]
	public var sectionStrings: [String] = []
	public var currentSelectContact: [ContactModel] = []
	public var selectMax = 8
	public var editContact: ContactModel?
	public var allContact: [ContactModel] = []

	public var midImage: UIImage = UIImage()
	public var lastImage: UIImage = UIImage()

	public let reloadTableViewRelay = PublishRelay<Bool>()

	override init() {
		super.init()

		let midlineView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 60))
		let lastLineView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 60))
		midImage = getMiddrawDotteLine(avatarView: midlineView)
		lastImage = getLastdrawDotteLine(avatarView: lastLineView)
	}

	public func layerUI() {

//		selectMax = BandManager.sharedInstance.contactMax
		CNContactStore().requestAccess(for: .contacts) { [weak self] (isAllow, _) in
			guard let self = self else { return }
			if isAllow {
				self.loadContactsData()
			}
		}
	}

	private func loadContactsData() {
		let status = CNContactStore.authorizationStatus(for: .contacts)

		guard status == .authorized else {
			return
		}

		let store = CNContactStore()

		let keys = [CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPhoneNumbersKey, CNContactOrganizationNameKey, CNContactThumbnailImageDataKey]

		let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor])

		var contacts: [ContactModel] = []
        
        DispatchQueue.main.async {
            do {
                log.debug("start loadContactsData")
                try store.enumerateContacts(with: request, usingBlock: { (contact, _) in
                    let identifier = contact.identifier
                    let lastName = contact.familyName
                    let firstName = contact.givenName
                    let phones = contact.phoneNumbers
                    let organization = contact.organizationName
                    _ = contact.thumbnailImageData

                    var phoneNumberArray: [String] = []
                    for phoneNumber in phones {
                        let number = phoneNumber.value.stringValue
                        phoneNumberArray.append(number)
                    }
                    var fullName = lastName + firstName
                    var isContains = false
                    for char in fullName.utf8 {
                        if (char > 64 && char < 91) || (char > 96 && char < 123) {
                            isContains = true
                            break
                        }
                    }
                    if isContains && lastName != "" && firstName != "" {
                        fullName = firstName + " " + lastName
                    }
                    if fullName == "" {
                        fullName = organization
                    }

                    if fullName == "" {
                        return
                    }

                    var image: UIImage = UIImage()
    //                if let data = imageData, let imageView = UIImage(data: data) {
    //                    image = imageView
    //                } else {
                        if let avatar = UIImage().createAvatarWith(name: fullName, color: R.color.settings_1_contacts_bg() ?? UIColor.black) {
                            image = avatar
                        }
    //                }
                    if phoneNumberArray.count > 0 {
                        if self.currentSelectContact.contains(where: { $0.fullName == fullName && phoneNumberArray.contains($0.selectPhoneNumber) }) {
                            if let edit = self.editContact, edit.fullName == fullName && edit.phoneNumbers.toArray() == phoneNumberArray {
                                log.debug("edit = \(edit.fullName)")
                            } else {
                                return
                            }
                        }
                        if contacts.contains(where: { $0.fullName == fullName && phoneNumberArray.contains($0.selectPhoneNumber) }) {
                            return
                        }
                        if phoneNumberArray.count > 1 {
                            for i in 0...phoneNumberArray.count {
                                var selectPhone = ""
                                if i != 0 {
                                    selectPhone = phoneNumberArray[i - 1]
                                }
                                let personContact = ContactModel(identifier: identifier, firstName: firstName, lastName: lastName, phoneNumbers: phoneNumberArray, fullName: fullName, organizationName: organization, selectPhoneNumber: selectPhone, imageData: image.pngData())
                                if self.currentSelectContact.contains(where: { $0.fullName == personContact.fullName && $0.selectPhoneNumber == personContact.selectPhoneNumber }) {
                                    if let edit = self.editContact, edit.fullName == fullName && edit.selectPhoneNumber == selectPhone {
                                        contacts.append(personContact)
                                    }
                                } else {
                                    contacts.append(personContact)
                                }

                            }
                        } else {
                            
                            let personContact = ContactModel(identifier: identifier, firstName: firstName, lastName: lastName, phoneNumbers: phoneNumberArray, fullName: fullName, organizationName: organization, selectPhoneNumber: phoneNumberArray[0], imageData: image.pngData())
                            if self.currentSelectContact.contains(where: { $0.fullName == personContact.fullName && $0.selectPhoneNumber == personContact.selectPhoneNumber }) {
                                if let edit = self.editContact, edit.fullName == fullName && edit.selectPhoneNumber == phoneNumberArray[0] {
                                    contacts.append(personContact)
                                }
                            } else {
                                contacts.append(personContact)
                            }

                        }

                    }
                })

            } catch {

            }
            log.debug("end loadContactsData = \(contacts.count)")
            self.allContact = contacts
            self.dataArray = self.sortData(From: contacts)
            self.reloadTableViewRelay.accept(true)
        }
		
	}

	public func filterBySubstring(str: String) {
		dataArray = sortData(From: allContact, filterStr: str)
		reloadTableViewRelay.accept(true)
	}

	private func sortData(From sourceDataArr: [ContactModel], filterStr: String = "") -> [String: [ContactModel]] {

		let indexedCollation = UILocalizedIndexedCollation.current()

		sectionStrings = indexedCollation.sectionTitles

		var sortedDataArr: [String: [ContactModel]] = [:]

		// 初始化数组“框架”（数组装数组）
		for str in sectionStrings {
			sortedDataArr[str] = []
		}

		// 将原数据根据指定方法放入到分组中
		for contact in sourceDataArr {
			if filterStr != "" {
				var isNumberContain = false
				if contact.phoneNumbers.count > 0 {
					for number in contact.phoneNumbers where number.contains(filterStr) {
                        isNumberContain = true
                        break
					}
				}
				if contact.fullName.contains(filterStr) || isNumberContain {
					let section = indexedCollation.section(for: contact, collationStringSelector: #selector(getter: ContactModel.fullName))
					sortedDataArr[sectionStrings[section]]?.append(contact)
				}
			} else {
				let section = indexedCollation.section(for: contact, collationStringSelector: #selector(getter: ContactModel.fullName))
				sortedDataArr[sectionStrings[section]]?.append(contact)
			}

		}

		// 对各分组按指定方法进行排序
		for str in sectionStrings {
			let sortedSubArr = indexedCollation.sortedArray(from: sortedDataArr[str] ?? [], collationStringSelector: #selector(getter: ContactModel.fullName))
			sortedDataArr[str] = sortedSubArr as? [ContactModel]
		}
		return sortedDataArr
	}

	public func numberOfSections() -> Int {
		return dataArray.count
	}

	public func numberOfRowsInSection(section: Int) -> Int {
		var count = 0
		if sectionStrings.count > section {
			let str = sectionStrings[section]
			if dataArray.keys.contains(str) {
				count = dataArray[str]!.count
			}
		}
		return count
	}

	public func titleForHeaderInSection(section: Int) -> String? {
		var title = ""
		if sectionStrings.count > section {
			let str = sectionStrings[section]
			if dataArray.keys.contains(str) {
				title = str
			}
		}
		return title
	}

	public func getCurrentContact(indexPath: IndexPath) -> ContactModel? {
		let row = indexPath.row
		let section = indexPath.section
		var contact: ContactModel?
		if sectionStrings.count > section {
			let str = sectionStrings[section]
			if dataArray.keys.contains(str) {
				if let sectionarray = dataArray[str], sectionarray.count > row {
					contact = sectionarray[row]
				}
			}
		}
		return contact
	}

	public func heightForHeaderInSection(section: Int) -> CGFloat {
		var height: CGFloat = 0
		if sectionStrings.count > section {
			let str = sectionStrings[section]
			if dataArray.keys.contains(str) {
				if let sectionarray = dataArray[str], sectionarray.count > 0 {
					height = 30
				}
			}
		}
		return height
	}

	public func didSelectRowAt(indexPath: IndexPath) {
		let contact = getCurrentContact(indexPath: indexPath)
		guard let currentContact = contact else {
			return
		}
		if currentContact.selectPhoneNumber == "" {
			return
		}

		if let index = currentSelectContact.firstIndex(where: { $0.phoneNumbers == currentContact.phoneNumbers && $0.fullName == currentContact.fullName }) {
			if currentSelectContact.firstIndex(where: { $0.phoneNumbers == currentContact.phoneNumbers && $0.fullName == currentContact.fullName && $0.selectPhoneNumber == currentContact.selectPhoneNumber }) != nil {
				if editContact == nil {
					currentSelectContact.remove(at: index)
				}
			} else {
				if editContact != nil {
					currentSelectContact[index] = currentContact
					editContact = currentContact
				} else {
					currentSelectContact.remove(at: index)
					currentSelectContact.append(currentContact)
				}

			}

		} else {
			if let edit = editContact {
				if let index = currentSelectContact.firstIndex(where: { $0.phoneNumbers == edit.phoneNumbers && $0.fullName == edit.fullName && $0.selectPhoneNumber == edit.selectPhoneNumber }) {
					currentSelectContact[index] = currentContact
					editContact = currentContact
				}
			} else if currentSelectContact.count < selectMax {
				currentSelectContact.append(currentContact)
			}
		}
		reloadTableViewRelay.accept(true)
	}

	private func getMiddrawDotteLine(avatarView: UIView) -> UIImage {
		let goalY = Double(avatarView.bounds.size.height)
		let goalX = Double(avatarView.bounds.size.width)

		let dotteShapLayer = CAShapeLayer()
		let mdotteShapePath = CGMutablePath()
		dotteShapLayer.fillColor = UIColor.clear.cgColor
        dotteShapLayer.strokeColor = R.color.common_23_text_second()?.cgColor
		dotteShapLayer.lineWidth = 1
		mdotteShapePath.move(to: CGPoint(x: goalX / 2, y: 0))
		mdotteShapePath.addLine(to: CGPoint(x: goalX / 2, y: goalY))
		mdotteShapePath.move(to: CGPoint(x: goalX / 2, y: goalY / 2))
		mdotteShapePath.addLine(to: CGPoint(x: goalX, y: goalY / 2))
		dotteShapLayer.path = mdotteShapePath
		let arr: NSArray = NSArray(array: [2, 1])
		dotteShapLayer.lineDashPhase = 1
		dotteShapLayer.lineDashPattern = arr as? [NSNumber]
		avatarView.layer.addSublayer(dotteShapLayer)
		return avatarView.screenShot() ?? UIImage()
	}

	private func getLastdrawDotteLine(avatarView: UIView) -> UIImage {
		let goalY = Double(avatarView.bounds.size.height)
		let goalX = Double(avatarView.bounds.size.width)

		let curveY = Double(avatarView.bounds.size.height) / 2 / 4 * 3
		let curveX = goalX / 2 + Double(avatarView.bounds.size.width) / 2 / 4 * 1

		let dotteShapLayer = CAShapeLayer()
		let mdotteShapePath = UIBezierPath()
		dotteShapLayer.fillColor = UIColor.clear.cgColor
        dotteShapLayer.strokeColor = R.color.common_23_text_second()?.cgColor
		dotteShapLayer.lineWidth = 1
		mdotteShapePath.move(to: CGPoint(x: goalX / 2, y: 0))
		mdotteShapePath.addLine(to: CGPoint(x: goalX / 2, y: curveY))
		mdotteShapePath.addQuadCurve(to: CGPoint(x: curveX, y: goalY / 2), controlPoint: CGPoint(x: goalX / 2, y: goalY / 2))
		mdotteShapePath.addLine(to: CGPoint(x: goalX, y: goalY / 2))
		dotteShapLayer.path = mdotteShapePath.cgPath
		let arr: NSArray = NSArray(array: [2, 1])
		dotteShapLayer.lineDashPhase = 1
		dotteShapLayer.lineDashPattern = arr as? [NSNumber]
		avatarView.layer.addSublayer(dotteShapLayer)
		return avatarView.screenShot() ?? UIImage()
	}
}
